#!/bin/bash
#服务器ip列表,以空格隔开
HOST="127.0.0.1"
#临时存放日志的位置
mkdir -p /tmp/batchExeLog/

#登录用户
user='root';
userPwd='rootPwd';
#前置命令
batchCMD="cd /home/admin;"

#并发进程数
THREAD_NUM=10
TEMP_FIFO=$$.fifo

#执行函数
EXEC(){

#判空命令介绍
if [[ "X" == $*"X" ]]
	then
		echo -e "\033[31m 命令介绍:\033[0m\n";
		echo -e "\033[33m   可将本地命令同时映射到多台服务器,并返回结果\033[0m";
		echo -e "\033[31m \t简单命令: \033[0m";
		echo -e "\033[33m \t\t例: xc pwd\033[0m";
		echo -e "\033[33m \t\t例: xc 'cd root;pwd;id root;'\033[0m";
		echo -e "\033[31m \t组合命令: \033[0m";
		echo -e "\033[33m \t\t输入: xc cmd \033[0m";
		echo -e "\033[33m \t\t出现: Enter your command: (在此输入完整命令后回车)\033[0m";
		return;
fi

#日志记录
echo -e $* >> /tmp/batchExeLog/history.log

if [[ "his" == $* ]]
	then
		echo -e "\033[31m 最近20次执行命令:\033[0m\n";
		hisCmd=`cat -n /tmp/batchExeLog/history.log | tail -n 20`;
		echo -e "\033[33m${hisCmd}\033[0m";
		return;
fi

#读取命令方式
if [[ "cmd" == $* ]]
	then
		echo -e "\033[31mEnter your command: \033[0m";
		read command;
		batchCMD=$batchCMD$command;
	else
		batchCMD=$batchCMD$*;
fi

#rm命令拦截
if [[ $batchCMD =~ "rm" ]]
	then
		echo -e "\033[31m 命令已被拦截: ${batchCMD}\033[0m\n";
		return;
fi
                
#定义描述符为996的管道,用于多线程
mkfifo $TEMP_FIFO
exec 996<>$TEMP_FIFO
rm -rf $TEMP_FIFO

#预先写10个位置,用于多线程
for ((i=0;i<$THREAD_NUM;i++))
do
    echo >&996
done

#计算耗时
start=$(date +%s%N)
start_ms=${start:0:16}

#时间戳,用于文件前缀
filePre=$(date "+%Y%m%d%H%M%S%N_")

for ip in $HOST
	do
		read -u996		#抢个位置
		{
			#同时执行命令,结果写入
			sshpass -p $userPwd ssh -o StrictHostKeyChecking=no $user@$ip -n "$batchCMD" > /tmp/batchExeLog/$filePre$ip".log"
			echo >&996		#腾个位置
		}&					#放入后台执行
done

echo -e "\033[31m 命令已发送...\033[0m";
echo -e "\033[31m 命令: ${batchCMD}\033[0m\n";

#等待多进程任务结束
wait

echo -e "\033[36m 结果已接收,正在分析...\033[0m";
for ip in $HOST
	do
		echo -e "\n\n\033[33m IP:${ip} \033[0m";
		echo -e "\033[33m ====================================================== \033[0m\n";
		cat /tmp/batchExeLog/$filePre$ip".log";
		rm -rf /tmp/batchExeLog/$filePre$ip".log";
done

end=$(date +%s%N)
end_ms=${end:0:16}

costTime=`echo "scale=0;($end_ms - $start_ms)/1000000" | bc`

echo -e "\n\033[31m 耗时:${costTime} 秒.\033[0m";
rm -rf $TEMP_FIFO;
}

EXEC $@